package com.xhs.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;

/**
 * @desc: CompletableFuture 异步回调案例
 * @projectName: java-tools-parent
 * @author: xhs
 * @date: 2025-08-09 周六 15:14
 */
@Slf4j
@RestController
@RequestMapping("/completableFutureCallback")
public class CompletableFutureCallbackController {

    @Resource
    private Executor taskExecutor;

    /**
     * thenRun执行完任务A，再执行任务B,A和B两个任务同一个线程执行 (系统自带线程池)
     */
    @GetMapping("/runAsyncThenRun")
    private void runAsyncThenRun() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
            try {
                log.info("任务A线程：" + Thread.currentThread().getName());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 再执行任务B
        }).thenRun(() -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
        });
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenRun执行完任务A，再执行任务B,A和B两个任务同一个线程执行 (指定线程池)  thenRunAsync
     */
    @GetMapping("/runAsyncThenRunWithExecutor")
    private void runAsyncThenRunWithExecutor() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
            try {
                log.info("任务A线程：" + Thread.currentThread().getName());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 再执行任务B
        }, taskExecutor).thenRun(() -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
        });
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenRunAsync执行完任务A，再执行任务B，A和B两个任务不是同一个线程
     */
    @GetMapping("/runAsyncThenRunAsync")
    private void runAsyncThenRunAsync() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
            try {
                log.info("任务A线程：" + Thread.currentThread().getName());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 再执行任务B
        }).thenRunAsync(() -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
        });
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenAccept和thenRun区别，thenAccept会接收上一个任务的结果作为参数,如果不指定线程池，使用main线程执行
     */
    @GetMapping("/thenAccept")
    private void thenAccept() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<Void> cf = CompletableFuture.supplyAsync(() -> {
            log.info("任务A线程：" + Thread.currentThread().getName());
            return "hello";
            // 再执行任务B
        }).thenAccept((param) -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
            log.info("任务B结果：{}  world", param);
        });
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenAcceptAsync和thenAccept的区别，thenAcceptAsync可以指定线程池
     */
    @GetMapping("/thenAcceptAsync")
    private void thenAcceptAsync() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<Void> cf = CompletableFuture.supplyAsync(() -> {
            log.info("任务A线程：" + Thread.currentThread().getName());
            return "hello";
            // 再执行任务B
        }).thenAcceptAsync((param) -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
            log.info("任务B结果：{}  world", param);
        },taskExecutor);
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenApply 接收上一个任务的结果作为参数，同时有返回值,不指定线程池则使用main线程执行
     * thenApplyAsync 则可以指定线程池执行
     */
    @GetMapping("/thenApply")
    private void thenApply() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
            log.info("任务A线程：" + Thread.currentThread().getName());
            return "hello";
            // 再执行任务B
        }).thenApply((param) -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
            log.info("任务B结果：{}  world", param);
            return param + " world";
        });
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }

    /**
     * thenApply 接收上一个任务的结果作为参数，同时有返回值,不指定线程池则使用main线程执行
     * thenApplyAsync 则可以指定线程池执行
     */
    @GetMapping("/thenApplyAsync")
    private void thenApplyAsync() throws ExecutionException, InterruptedException {
        // 执行任务A
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
            log.info("任务A线程：" + Thread.currentThread().getName());
            return "hello";
            // 再执行任务B
        }).thenApplyAsync((param) -> {
            log.info("任务B线程：" + Thread.currentThread().getName());
            log.info("任务B结果：{}  world", param);
            return param + " world";
        },taskExecutor);
        // get方法测试
        log.info("get方法测试:{}", cf.get());
    }
}
